import java.util.*;

public class Function {
    private static Function instance = new Function();

    private Function() {

    }

    public static Function getInstance() {
        return instance;
    }

    TokenUtils tokenUtils = TokenUtils.getInstance();
    int XCount = -1;
    Stack<Integer> condStack = new Stack<Integer>();                        //cond中记录最近的结果
    Stack<Integer> arrayStack = new Stack<Integer>();                         //计算array索引

    Stack<Integer> outIfBlockId = new Stack<Integer>();                     //记录当前if的外层块
    Stack<Integer> nowIfBlockId = new Stack<Integer>();                     //记录当前if的同级块

    Stack<Integer> outWhileBlockId = new Stack<Integer>();                     //记录当前while的外层块
    Stack<Integer> nowWhileBlockId = new Stack<Integer>();                     //记录当前while的同级块
    Stack<Integer> judgeWhileBlockId = new Stack<Integer>();                     //记录当前while的判断块
    List<Map<String, Object>> identMapList = new LinkedList<Map<String, Object>>();
    List<Map<String, Object>> constIdentMapList = new LinkedList<Map<String, Object>>();
    Map<String, Integer> identMap = new HashMap<String, Integer>();
    Map<String, Integer> constIdentMap = new HashMap<String, Integer>();
    Map<String, Integer> globalExpMap = new HashMap<String, Integer>();

    List<Map<String, Object>> arrayMapList = new LinkedList<Map<String, Object>>();
    List<Map<String, Object>> constArrayMapList = new LinkedList<Map<String, Object>>();
    Map<String, List<Integer>> arrayMap = new HashMap<String, List<Integer>>();
    Map<String, List<Integer>> constArrayMap = new HashMap<String, List<Integer>>();

    Map<String, List<Integer>> funcParamsMap = new HashMap<String, List<Integer>>();
    boolean haveRet = false;


    List<String> paramsArrayList = new LinkedList<String>();

    boolean isParam(Object key) {
        for (String str : paramsArrayList) {
            if (str.equals(key)) {
                return true;
            }
        }
        return false;
    }


    boolean containsIdent(Object key) {
        Map<String, Object> map = null;
        for (int i = identMapList.size() - 1; i >= 0; i--) {
            map = identMapList.get(i);
            if (map.containsKey(key)) {
                return true;
            }
        }
        return false;
    }

    int a;

    Object getIdentValue(Object key) {
        Map<String, Object> map = null;
        for (int i = identMapList.size() - 1; i >= 0; i--) {
            map = identMapList.get(i);
            if (map.containsKey(key)) {
                return map.get(key);
            }
        }
        return null;
    }

    boolean containsConstIdent(Object key) {
        Map<String, Object> map = null;
        for (int i = constIdentMapList.size() - 1; i >= 0; i--) {
            map = constIdentMapList.get(i);
            if (map.containsKey(key)) {
                return true;
            }
        }
        return false;
    }

    Object getConstIdentValue(Object key) {
        Map<String, Object> map = null;
        for (int i = constIdentMapList.size() - 1; i >= 0; i--) {
            map = constIdentMapList.get(i);
            if (map.containsKey(key)) {
                return map.get(key);
            }
        }
        return null;
    }

    boolean containsArray(Object key) {
        Map<String, Object> map = null;
        for (int i = arrayMapList.size() - 1; i >= 0; i--) {
            map = arrayMapList.get(i);
            if (map.containsKey(key)) {
                return true;
            }
        }
        return false;
    }

    Object getArrayValue(Object key) {
        Map<String, Object> map = null;
        for (int i = arrayMapList.size() - 1; i >= 0; i--) {
            map = arrayMapList.get(i);
            if (map.containsKey(key)) {
                return map.get(key);
            }
        }
        return null;
    }

    boolean containsConstArray(Object key) {
        Map<String, Object> map = null;
        for (int i = constArrayMapList.size() - 1; i >= 0; i--) {
            map = constArrayMapList.get(i);
            if (map.containsKey(key)) {
                return true;
            }
        }
        return false;
    }

    Object getConstArrayValue(Object key) {
        Map<String, Object> map = null;
        for (int i = constArrayMapList.size() - 1; i >= 0; i--) {
            map = constArrayMapList.get(i);
            if (map.containsKey(key)) {
                return map.get(key);
            }
        }
        return null;
    }

    int arrayLenth(List<Object> list) {
        int ans = 1, len = list.size();
        for (int i = 1; i < len; i++) {
            ans *= (Integer) list.get(i);
        }
        return ans;
    }


    public void compUnit() {
        System.out.println("declare i32 @getarray(i32*)\n" +
                "declare void @putarray(i32, i32*)\n" +
                "declare i32 @getint()\n" +
                "declare void @putint(i32)\n" +
                "declare i32 @getch()\n" +
                "declare void @putch(i32)" +
                "declare void @memset(i32*, i32, i32)"
        );
        funcParamsMap.put("getint", new ArrayList<Integer>(Arrays.asList()));
        funcParamsMap.put("putint", new ArrayList<Integer>(Arrays.asList(0)));
        funcParamsMap.put("getch", new ArrayList<Integer>(Arrays.asList()));
        funcParamsMap.put("putch", new ArrayList<Integer>(Arrays.asList(0)));
        funcParamsMap.put("getarray", new ArrayList<Integer>(Arrays.asList(1)));
        funcParamsMap.put("putarray", new ArrayList<Integer>(Arrays.asList(0, 1)));


        identMapList.add(new HashMap<String, Object>());
        constIdentMapList.add(new HashMap<String, Object>());
        arrayMapList.add(new HashMap<String, Object>());
        constArrayMapList.add(new HashMap<String, Object>());
        while (tokenUtils.getCurrentPosition() < tokenUtils.getAllText().size() - 1) {
            if (!tokenUtils.peekThree().equals("(")) {
                this.decl(true);
            } else {
                this.funcDef();
            }
        }
    }

    public void block(boolean isFromIf, Map<String, Object> paramsIdentMap, Map<String, Object> paramsArrayMap, int deep, String funcName) {

        for (String name : paramsIdentMap.keySet()) {
            if (!paramsArrayMap.containsKey(name)) {
                int id = ++this.XCount;
                System.out.println("%x" + id + " = alloca i32");
                System.out.println("store i32 %x" + paramsIdentMap.get(name) + ", i32* %x" + id);
                paramsIdentMap.put(name, id);
            }
        }

        identMapList.add(paramsIdentMap);
        constIdentMapList.add(new HashMap<String, Object>());
        arrayMapList.add(paramsArrayMap);
        constArrayMapList.add(new HashMap<String, Object>());

        paramsArrayList.addAll(paramsArrayMap.keySet());

        if (!tokenUtils.getNext().equals("{")) {
            System.exit(15);
        }

        while (isBlockItem()) {
            this.blockItem(identMap, constIdentMap, isFromIf, deep, funcName);
        }

        if (!tokenUtils.getNext().equals("}")) {
            System.exit(16);
        }

        identMapList.remove(identMapList.size() - 1);
        constIdentMapList.remove(constIdentMapList.size() - 1);
        arrayMapList.remove(arrayMapList.size() - 1);
        constArrayMapList.remove(constArrayMapList.size() - 1);

        if (deep == 1) {
            paramsArrayList.clear();
            if (!haveRet) {
                if (tokenUtils.getFuncIdent().get(funcName).get(0).equals("void")) {
                    System.out.println("ret void");
                } else {
                    System.out.println("ret i32 0");
                }
            }
            haveRet = false;
        }
    }

    public boolean isBlockItem() {
        Object obj = tokenUtils.peek();
        return obj.equals("const") || obj.equals("int") || obj.equals("return") || obj.equals("if") || obj.equals("{") || obj.equals("continue") || obj.equals("break") || obj.equals("while") || tokenUtils.isInExp(obj);
    }

    public void blockItem(Map<String, Integer> identMap, Map<String, Integer> constIdentMap, boolean isFromIf, int deep, String funcName) {
        if (tokenUtils.peek().equals("const") || tokenUtils.peek().equals("int")) {
            this.decl(false);
        } else {
            this.stmt(outIfBlockId.isEmpty() ? null : outIfBlockId.peek(), isFromIf ? null : (nowIfBlockId.isEmpty() ? null : nowIfBlockId.peek()), deep, funcName);
        }
    }

    public void decl(boolean isGlobal) {
        if (tokenUtils.peek().equals("const")) {
            this.constDecl(isGlobal);
        } else if (tokenUtils.peek().equals("int")) {
            this.varDecl(isGlobal);
        }
    }

    public void constDecl(boolean isGlobal) {
        if (!tokenUtils.getNext().equals("const")) {
            System.exit(17);
        }

        this.Btype();

        if (isGlobal) {
            this.globalConstDef();
        } else {
            this.constDef();
        }


        while (tokenUtils.getNext().equals(",")) {
            if (isGlobal) {
                this.globalConstDef();
            } else {
                this.constDef();
            }
        }

        if (!tokenUtils.getCurrent().equals(";")) {
            System.exit(18);
        }

    }

    public void varDecl(boolean isGlobal) {
        this.Btype();

        if (isGlobal) {
            this.globalVarDef();
        } else {
            this.varDef();
        }


        while (tokenUtils.getNext().equals(",")) {
            if (isGlobal) {
                this.globalVarDef();
            } else {
                this.varDef();
            }
        }

        if (!tokenUtils.getCurrent().equals(";")) {
            System.exit(19);
        }
    }

    public void Btype() {
        if (!tokenUtils.getNext().equals("int")) {
            System.exit(20);
        }
    }

    public void arrayDef(Object ident) {
        List<Object> list = new ArrayList<Object>();
        list.add(0);
        while (tokenUtils.peek().equals("[")) {
            tokenUtils.getNext();
            //检查是否在编译期可求值
            for (int i = tokenUtils.getCurrentPosition(); !(tokenUtils.getAllText().get(i).equals("]") || tokenUtils.getAllText().get(i).equals(";")); i++) {
                if (containsIdent(tokenUtils.getAllText().get(i)) && !containsConstIdent(tokenUtils.getAllText().get(i))
                        || tokenUtils.getFuncIdent().containsKey(tokenUtils.getAllText().get(i))) {
                    System.exit(51);
                }
            }
            int value = this.globalExp();
            if (!tokenUtils.getNext().equals("]")) {
                System.exit(52);
            }
            list.add(value);
        }
        int len = list.size(), arrayLen = 1;
        for (int i = 1; i < len; i++) {
            arrayLen *= (Integer) list.get(i);
        }
        identMapList.get(identMapList.size() - 1).put((String) ident, ++this.XCount);
        list.set(0, this.XCount);
        arrayMapList.get(arrayMapList.size() - 1).put((String) ident, list);
        System.out.println("%x" + this.XCount + " = alloca [" + arrayLen + " x i32]");
        System.out.println("%x" + (++this.XCount) + " = getelementptr [" + arrayLen + " x i32], [" + arrayLen + " x i32]* %x" + list.get(0) + ", i32 0, i32 0");
        System.out.println("call void @memset(i32* %x" + this.XCount + ", i32 0, i32 " + (4 * arrayLen) + ")");
    }

    public void constArrayDef(Object ident) {
        List<Object> list = new ArrayList<Object>();
        list.add(0);
        while (tokenUtils.peek().equals("[")) {
            tokenUtils.getNext();
            //检查是否在编译期可求值
            for (int i = tokenUtils.getCurrentPosition(); !(tokenUtils.getAllText().get(i).equals("]") || tokenUtils.getAllText().get(i).equals(";")); i++) {
                if (containsIdent(tokenUtils.getAllText().get(i)) && !containsConstIdent(tokenUtils.getAllText().get(i))
                        || tokenUtils.getFuncIdent().containsKey(tokenUtils.getAllText().get(i))) {
                    System.exit(53);
                }
            }
            int value = this.globalExp();
            if (!tokenUtils.getNext().equals("]")) {
                System.exit(54);
            }
            list.add(value);
        }
        int len = list.size(), arrayLen = 1;
        for (int i = 1; i < len; i++) {
            arrayLen *= (Integer) list.get(i);
        }
        identMapList.get(identMapList.size() - 1).put((String) ident, ++this.XCount);
        list.set(0, this.XCount);
        constArrayMapList.get(constArrayMapList.size() - 1).put((String) ident, list);
        System.out.println("%x" + this.XCount + " = alloca [" + arrayLen + " x i32]");
        System.out.println("%x" + (++this.XCount) + " = getelementptr [" + arrayLen + " x i32], [" + arrayLen + " x i32]* %x" + list.get(0) + ", i32 0, i32 0");
        System.out.println("call void @memset(i32* %x" + this.XCount + ", i32 0, i32 " + (4 * arrayLen) + ")");
    }

    public void globalArrayDef(Object ident) {
        List<Object> list = new ArrayList<Object>();
        list.add(0);
        while (tokenUtils.peek().equals("[")) {
            tokenUtils.getNext();
            //检查是否在编译期可求值
            for (int i = tokenUtils.getCurrentPosition(); !(tokenUtils.getAllText().get(i).equals("]") || tokenUtils.getAllText().get(i).equals(";")); i++) {
                if (containsIdent(tokenUtils.getAllText().get(i)) && !containsConstIdent(tokenUtils.getAllText().get(i))
                        || tokenUtils.getFuncIdent().containsKey(tokenUtils.getAllText().get(i))) {
                    System.exit(51);
                }
            }
            int value = this.globalExp();
            if (!tokenUtils.getNext().equals("]")) {
                System.exit(52);
            }
            list.add(value);
        }
        int len = list.size(), arrayLen = 1;
        for (int i = 1; i < len; i++) {
            arrayLen *= (Integer) list.get(i);
        }
        identMapList.get(identMapList.size() - 1).put((String) ident, "@" + (String) ident);
        list.set(0, "@" + (String) ident);
        arrayMapList.get(arrayMapList.size() - 1).put((String) ident, list);
    }

    public void globalConstArrayDef(Object ident) {
        List<Object> list = new ArrayList<Object>();
        list.add(0);
        while (tokenUtils.peek().equals("[")) {
            tokenUtils.getNext();
            //检查是否在编译期可求值
            for (int i = tokenUtils.getCurrentPosition(); !(tokenUtils.getAllText().get(i).equals("]") || tokenUtils.getAllText().get(i).equals(";")); i++) {
                if (containsIdent(tokenUtils.getAllText().get(i)) && !containsConstIdent(tokenUtils.getAllText().get(i))
                        || tokenUtils.getFuncIdent().containsKey(tokenUtils.getAllText().get(i))) {
                    System.exit(53);
                }
            }
            int value = this.globalExp();
            if (!tokenUtils.getNext().equals("]")) {
                System.exit(54);
            }
            list.add(value);
        }
        int len = list.size(), arrayLen = 1;
        for (int i = 1; i < len; i++) {
            arrayLen *= (Integer) list.get(i);
        }
        identMapList.get(identMapList.size() - 1).put((String) ident, "@" + (String) ident);
        list.set(0, "@" + (String) ident);
        constArrayMapList.get(constArrayMapList.size() - 1).put((String) ident, list);
    }

    public void arrayInit(List<Object> list, int firstIndex, int deep) {
        int len = arrayLenth(list);
        if (!tokenUtils.getNext().equals("{")) {
            System.exit(55);
        }
        if (tokenUtils.peek().equals("}")) {
            tokenUtils.getNext();
            return;
        }
        int i = 0;
        do {
            if (tokenUtils.peek().equals("{")) {
                int tmp = 1;
                for (int j = list.size() - 1; j > deep + 1; j--) {
                    tmp *= (Integer) list.get(j);
                }
                this.arrayInit(list, firstIndex + i * tmp, deep + 1);
            } else {
                if (firstIndex + i >= len) {
                    System.exit(56);
                }
                int nowIndex = ++this.XCount;
                System.out.println("%x" + nowIndex + " = getelementptr [" + len + " x i32], [" + len + " x i32]* %x" + list.get(0) + ", i32 0, i32 " + (firstIndex + i));
                exp(0, false);
                System.out.println("store i32 %x" + this.XCount + ",i32* %x" + nowIndex);
            }
            i++;
        } while (tokenUtils.getNext().equals(","));
    }

    public List<Map<Integer, Integer>> getGlobalFlagList(List<Object> list, List<Map<Integer, Integer>> flagList, int firstIndex, int deep) {
        int len = arrayLenth(list);
        if (!tokenUtils.getNext().equals("{")) {
            System.exit(55);
        }
        if (tokenUtils.peek().equals("}")) {
            tokenUtils.getNext();
            return flagList;
        }
        int i = 0;
        do {
            if (tokenUtils.peek().equals("{")) {
                int tmp = 1;
                for (int j = list.size() - 1; j > deep + 1; j--) {
                    tmp *= (Integer) list.get(j);
                }
                this.getGlobalFlagList(list, flagList, firstIndex + i * tmp, deep + 1);
            } else {
                if (firstIndex + i >= len) {
                    System.exit(56);
                }
                Map<Integer, Integer> map = new HashMap<Integer, Integer>();
                map.put((firstIndex + i), (Integer) tokenUtils.getNext());
                flagList.add(map);
            }
            i++;
        } while (tokenUtils.getNext().equals(","));
        return flagList;
    }

    public int getIndexValue(List<Map<Integer, Integer>> flagList, int index) {
        for (Map<Integer, Integer> map : flagList) {
            if (map.containsKey(index)) {
                return map.get(index);
            }
        }
        return 0;
    }

    public void globalArrayInit(List<Object> list) {
        List<Map<Integer, Integer>> tmpList = new ArrayList<Map<Integer, Integer>>();
        List<Map<Integer, Integer>> flagList = getGlobalFlagList(list, tmpList, 0, 0);
        int len = arrayLenth(list);
        System.out.print(list.get(0) + " = global [" + len + " x i32] [");
        for (int i = 0; i < len - 1; i++) {
            System.out.print("i32 " + this.getIndexValue(flagList, i) + ", ");
        }
        System.out.println("i32 " + this.getIndexValue(flagList, len - 1) + "]");
    }

    public void varDef() {
        if (!tokenUtils.isIdent(tokenUtils.getNext())) {
            System.exit(21);
        }
        Object ident = tokenUtils.getCurrent();
        if (identMapList.get(identMapList.size() - 1).get(ident) != null) {
            System.exit(22);
        }
        if (tokenUtils.peek().equals("[")) {
            this.arrayDef(ident);
        } else {
            identMapList.get(identMapList.size() - 1).put((String) ident, ++this.XCount);
            System.out.println("%x" + this.XCount + " = alloca i32");
        }
        if (tokenUtils.peek().equals("=")) {
            tokenUtils.getNext();
            if (arrayMapList.get(arrayMapList.size() - 1).get(ident) != null) {
                this.arrayInit((List<Object>) arrayMapList.get(arrayMapList.size() - 1).get(ident), 0, 0);
            } else {
                this.exp(0, false);
                if (getIdentValue(ident) instanceof Integer) {
                    System.out.println("store i32 %x" + this.XCount + ", i32* %x" + getIdentValue(ident));
                } else {
                    System.out.println("store i32 %x" + this.XCount + ", i32* " + getIdentValue(ident));
                }
            }
        }
    }

    public void globalVarDef() {
        if (!tokenUtils.isIdent(tokenUtils.getNext())) {
            System.exit(23);
        }
        Object ident = tokenUtils.getCurrent();
        if (identMapList.get(identMapList.size() - 1).get(ident) != null) {
            System.exit(24);
        }
        if (tokenUtils.peek().equals("[")) {
            this.globalArrayDef(ident);
        } else {
            identMapList.get(identMapList.size() - 1).put((String) ident, "@" + (String) ident);
        }

        if (tokenUtils.peek().equals("=")) {
            tokenUtils.getNext();
            if (arrayMapList.get(arrayMapList.size() - 1).get(ident) != null) {
                globalArrayInit((List<Object>) arrayMapList.get(arrayMapList.size() - 1).get(ident));
            } else {
                //检查是否在编译期可求值
                for (int i = tokenUtils.getCurrentPosition(); !(tokenUtils.getAllText().get(i).equals(",") || tokenUtils.getAllText().get(i).equals(";")); i++) {
                    if (containsIdent(tokenUtils.getAllText().get(i)) && !containsConstIdent(tokenUtils.getAllText().get(i))
                            || tokenUtils.getFuncIdent().containsKey(tokenUtils.getAllText().get(i))) {
                        System.exit(25);
                    }
                }
                int value = this.globalExp();
                System.out.println("@" + ident + " = " + "global i32 " + value);
                this.globalExpMap.put((String) ident, value);
            }
        } else {
            if (arrayMapList.get(arrayMapList.size() - 1).get(ident) != null) {
                List<Object> list = (List<Object>) arrayMapList.get(arrayMapList.size() - 1).get(ident);
                int len = list.size(), arrayLen = 1;
                for (int i = 1; i < len; i++) {
                    arrayLen *= (Integer) list.get(i);
                }
                System.out.println("@" + ident + " = " + "global [" + arrayLen + " x i32] zeroinitializer");
            } else {
                System.out.println("@" + ident + " = " + "global i32 0");
                this.globalExpMap.put((String) ident, 0);
            }
        }
    }

    public void constDef() {
        if (!tokenUtils.isIdent(tokenUtils.getNext())) {
            System.exit(26);
        }
        Object ident = tokenUtils.getCurrent();
        if (identMapList.get(identMapList.size() - 1).get(ident) != null) {
            System.exit(27);
        }
        if (tokenUtils.peek().equals("[")) {
            this.constArrayDef(ident);
        } else {
            identMapList.get(identMapList.size() - 1).put((String) ident, ++this.XCount);
            constIdentMapList.get(constIdentMapList.size() - 1).put((String) ident, this.XCount);
            System.out.println("%x" + this.XCount + " = alloca i32");
        }

        if (!tokenUtils.getNext().equals("=")) {
            System.exit(28);
        }
        if (constArrayMapList.get(constArrayMapList.size() - 1).get(ident) != null) {
            this.arrayInit((List<Object>) constArrayMapList.get(constArrayMapList.size() - 1).get(ident), 0, 0);
        } else {
            int val = this.constInitVal();
            this.globalExpMap.put((String) ident, val);
            if (getIdentValue(ident) instanceof Integer) {
                System.out.println("store i32 %x" + this.XCount + ", i32* %x" + getIdentValue(ident));
            } else {
                System.out.println("store i32 %x" + this.XCount + ", i32* " + getIdentValue(ident));
            }
        }
    }

    public void globalConstDef() {
        if (!tokenUtils.isIdent(tokenUtils.getNext())) {
            System.exit(29);
        }
        Object ident = tokenUtils.getCurrent();
        if (identMapList.get(identMapList.size() - 1).get(ident) != null) {
            System.exit(30);
        }
        if (tokenUtils.peek().equals("[")) {
            this.globalConstArrayDef(ident);
        } else {
            identMapList.get(identMapList.size() - 1).put((String) ident, "@" + (String) ident);
            constIdentMapList.get(constIdentMapList.size() - 1).put((String) ident, "@" + (String) ident);
        }


        if (tokenUtils.peek().equals("=")) {
            tokenUtils.getNext();
            if (constArrayMapList.get(constArrayMapList.size() - 1).get(ident) != null) {
                globalArrayInit((List<Object>) constArrayMapList.get(constArrayMapList.size() - 1).get(ident));
            } else {
                //检查是否在编译期可求值
                for (int i = tokenUtils.getCurrentPosition(); !(tokenUtils.getAllText().get(i).equals(",") || tokenUtils.getAllText().get(i).equals(";")); i++) {
                    if (containsIdent(tokenUtils.getAllText().get(i)) && !containsConstIdent(tokenUtils.getAllText().get(i))
                            || tokenUtils.getFuncIdent().containsKey(tokenUtils.getAllText().get(i))) {
                        System.exit(31);
                    }
                }
                int value = this.globalExp();
                System.out.println("@" + ident + " = " + "global i32 " + value);
                this.globalExpMap.put((String) ident, value);
            }
        } else {
            if (constArrayMapList.get(constArrayMapList.size() - 1).get(ident) != null) {
                List<Object> list = (List<Object>) constArrayMapList.get(constArrayMapList.size() - 1).get(ident);
                int len = list.size(), arrayLen = 1;
                for (int i = 1; i < len; i++) {
                    arrayLen *= (Integer) list.get(i);
                }
                System.out.println("@" + ident + " = " + "constant [" + arrayLen + " x i32] zeroinitializer");
            } else {
                System.out.println("@" + ident + " = " + "global i32 0");
                this.globalExpMap.put((String) ident, 0);
            }
        }
    }

    public int constInitVal() {
        int initPos = tokenUtils.getCurrentPosition();
        int val = this.globalExp();
        tokenUtils.setCurrentPosition(initPos);
        this.constExp();
        return val;
    }

    public void constExp() {
        for (int i = tokenUtils.getCurrentPosition(); !(tokenUtils.getAllText().get(i).equals(",") || tokenUtils.getAllText().get(i).equals(";")); i++) {
            if (containsIdent(tokenUtils.getAllText().get(i)) && !containsConstIdent(tokenUtils.getAllText().get(i))
                    || tokenUtils.getFuncIdent().containsKey(tokenUtils.getAllText().get(i))) {
                System.exit(32);
            }
        }
        this.exp(0, false);
    }

    public void stmt(Integer outBlockId, Integer nowBlockId, int deep, String funcName) {
        if (outBlockId != null && nowBlockId != null) {
            System.out.println("x" + nowBlockId + ":");
        }
        Object ident = null;
        int ptr = 0;
        if (containsIdent(tokenUtils.peek())) {
            Object identTmp = tokenUtils.getNext();
            if (containsConstIdent(identTmp) && tokenUtils.peek().equals("=")) {                    //如果是常量赋值
                System.exit(33);
            } else if (!tokenUtils.peek().equals("=") && !tokenUtils.peek().equals("[")) {                                            //如果不是赋值
                tokenUtils.getBack();
            } else if (containsConstArray(identTmp)) {                                              //如果是常量数组赋值
                System.exit(60);
            } else if (containsArray(identTmp)) {
                ident = tokenUtils.getCurrent();
                tokenUtils.getNext();
                ptr = getArrayPtr(ident, 0);
            } else {
                ident = tokenUtils.getCurrent();
                tokenUtils.getNext();
            }
            exp(0, false);
            if (!tokenUtils.getNext().equals(";")) {
                System.exit(34);
            }
        } else if (tokenUtils.peek().equals("return")) {
            tokenUtils.getNext();
            if (tokenUtils.getFuncIdent().get(funcName).get(0).equals("void")) {
                System.out.println("ret void");
            } else {
                exp(0, false);
                System.out.println("ret " + "i32 %x" + this.XCount);
            }

            haveRet = true;
            if (!tokenUtils.getNext().equals(";")) {
                System.exit(35);
            }
        } else if (tokenUtils.peek().equals("if")) {
            Object objElse = tokenUtils.getCurrent();//保存上一词，看看是不是else
            tokenUtils.getNext();
            if (!tokenUtils.getNext().equals("(")) {
                System.exit(36);
            }
            cond();
            int ansCount = this.XCount;
            System.out.println("%x" + (++this.XCount) + " =" + " icmp ne i32 %x" + ansCount + ",0");

            if (!tokenUtils.getNext().equals(")")) {
                System.exit(37);
            }
            System.out.print("br i1" + " %x" + this.XCount);

            Integer trueBlockId = ++this.XCount, falseBlockId = ++this.XCount;
            System.out.print(",label %x" + trueBlockId);
            System.out.println(",label %x" + falseBlockId);
            this.nowIfBlockId.push(falseBlockId);
            this.nowIfBlockId.push(trueBlockId);


            if (!objElse.equals("else")) {//如果是else if 就不增加层数
                this.outIfBlockId.push(++this.XCount);
            }


            stmt(this.outIfBlockId.peek(), this.nowIfBlockId.pop(), deep, funcName);
            System.out.println("br label %x" + this.outIfBlockId.peek());

            if (tokenUtils.peek().equals("else")) {
                tokenUtils.getNext();
                Object objIf = tokenUtils.peek();//保存是不是else if
                stmt(this.outIfBlockId.peek(), this.nowIfBlockId.pop(), deep, funcName);
                if (!objIf.equals("if")) {
                    System.out.println("br label %x" + this.outIfBlockId.peek());
                    System.out.println("x" + this.outIfBlockId.pop() + ":");//如果是else if，层数会在最后一个else if减少，因此返回时不需要减少层数
                    if (deep == 1 && tokenUtils.peek().equals("}")) {
                        if (tokenUtils.getFuncIdent().get(funcName).get(0).equals("void")) {
                            System.out.println("ret void");
                        } else {
                            System.out.println("ret i32 0");
                        }
                        haveRet = true;
                    }
                }
            } else {
                System.out.println("x" + this.nowIfBlockId.pop() + ":");
                System.out.println("br label %x" + this.outIfBlockId.peek());
                System.out.println("x" + this.outIfBlockId.pop() + ":");
            }


        } else if (tokenUtils.peek().equals("while")) {
            tokenUtils.getNext();
            if (!tokenUtils.getNext().equals("(")) {
                System.exit(53);
            }
            judgeWhileBlockId.push(++this.XCount);
            nowWhileBlockId.push(++this.XCount);
            outWhileBlockId.push(++this.XCount);
            System.out.println("br label %x" + judgeWhileBlockId.peek());
            System.out.println("x" + judgeWhileBlockId.peek() + ":");
            this.cond();
            int ansCount = this.XCount;
            System.out.println("%x" + (++this.XCount) + " =" + " icmp ne i32 %x" + ansCount + ",0");
            if (!tokenUtils.getNext().equals(")")) {
                System.exit(54);
            }
            System.out.print("br i1" + " %x" + this.XCount);
            System.out.print(",label %x" + nowWhileBlockId.peek());
            System.out.println(",label %x" + outWhileBlockId.peek());
            this.stmt(outWhileBlockId.peek(), nowWhileBlockId.peek(), deep, funcName);
            System.out.println("br label %x" + judgeWhileBlockId.pop());
            System.out.println("x" + outWhileBlockId.pop() + ":");
            nowWhileBlockId.pop();
            if (deep == 1 && tokenUtils.peek().equals("}")) {
                if (tokenUtils.getFuncIdent().get(funcName).get(0).equals("void")) {
                    System.out.println("ret void");
                } else {
                    System.out.println("ret i32 0");
                }
                haveRet = true;
            }

        } else if (tokenUtils.peek().equals("continue")) {
            tokenUtils.getNext();
            System.out.println("br label %x" + judgeWhileBlockId.peek());
            if (!tokenUtils.getNext().equals(";")) {
                System.exit(51);
            }
        } else if (tokenUtils.peek().equals("break")) {
            tokenUtils.getNext();
            System.out.println("br label %x" + outWhileBlockId.peek());
            if (!tokenUtils.getNext().equals(";")) {
                System.exit(52);
            }
        } else if (tokenUtils.peek().equals("{")) {
            this.block(true, new HashMap<String, Object>(), new HashMap<String, Object>(), deep + 1, funcName);

        } else {
            if (!tokenUtils.peek().equals(";")) {
                exp(0, false);
            }
            if (!tokenUtils.getNext().equals(";")) {
                System.exit(38);
            }
        }
        if (ident != null) {
            if (containsArray(ident)) {
                System.out.println("store i32 %x" + this.XCount + ", i32* %x" + ptr);
            } else {
                if (getIdentValue(ident) instanceof Integer) {
                    System.out.println("store i32 %x" + this.XCount + ", i32* %x" + getIdentValue(ident));
                } else {
                    System.out.println("store i32 %x" + this.XCount + ", i32* " + getIdentValue(ident));
                }
            }

        }


    }

    public void cond() {
        Stack<String> stack = new Stack<String>();
        tokenUtils.getNext();
        int flag = 0, NumCount = 0;
        int position = 0;
        while (true) {
            flag = 0;
            if (stack.empty() && !tokenUtils.isInCondExp(tokenUtils.getCurrent())) {
                if (NumCount != 1) {
                    System.exit(39);
                }
                break;
            }
            if (stack.empty()) {
                if (tokenUtils.isInExp(tokenUtils.getCurrent()) || tokenUtils.getCurrent() instanceof Integer || containsIdent(tokenUtils.getCurrent()) || tokenUtils.isFunction(tokenUtils.getCurrent())) {
                    tokenUtils.getBack();
                    exp(2, false);
                    this.condStack.push(this.XCount);
                    NumCount++;
                    tokenUtils.getNext();
                } else {
                    stack.push((String) tokenUtils.getCurrent());
                    tokenUtils.getNext();
                }
            } else if (!tokenUtils.isInCondExp(tokenUtils.getCurrent())) {
                if (stack.peek().equals("(")) {
                    System.exit(40);
                } else {
                    NumCount--;
                    condPrint(stack.pop());
                }
            } else {
                if (tokenUtils.getIsCondPush().get(stack.peek()) != null) {
                    for (String string : tokenUtils.getIsCondPush().get(stack.peek())) {
                        if (tokenUtils.getCurrent().equals(string)) {
                            stack.push(string);
                            tokenUtils.getNext();
                            flag = 1;
                            break;
                        } else if ((tokenUtils.isInExp(tokenUtils.getCurrent()) || tokenUtils.getCurrent() instanceof Integer || containsIdent(tokenUtils.getCurrent()) || tokenUtils.isFunction(tokenUtils.getCurrent())) && string.equals("NNN")) {
                            tokenUtils.getBack();
                            exp(2, false);
                            this.condStack.push(this.XCount);
                            NumCount++;
                            tokenUtils.getNext();
                            flag = 1;
                            break;
                        }
                    }
                }
                if (flag != 1) {
                    for (String string : tokenUtils.getIsCondPop().get(stack.peek())) {
                        if (tokenUtils.getCurrent().equals(string)) {
                            NumCount--;
                            condPrint(stack.pop());
                            flag = 1;
                            break;
                        }
                    }
                    if (flag == 0) {
                        System.exit(41);
                    }
                }
            }
        }
        tokenUtils.getBack();
    }

    public void condPrint(Object obj) {
        Integer a, b;
        if (obj.equals("||")) {
            //规范输入为i1
            b = this.condStack.pop();
            a = this.condStack.pop();
            System.out.println("%x" + (++this.XCount) + " =" + " icmp ne i32 %x" + b + ",0");
            this.condStack.push(this.XCount);
            System.out.println("%x" + (++this.XCount) + " =" + " icmp ne i32 %x" + a + ",0");
            this.condStack.push(this.XCount);
            //按位或
            System.out.println("%x" + (++this.XCount) + " =" + " or i1" + " %x" + this.condStack.pop() + ", %x" + this.condStack.pop());
            this.condStack.push(this.XCount);
            //规范结果为i32
            System.out.println("%x" + (++this.XCount) + " =" + " zext i1" + " %x" + this.condStack.pop() + " to i32");
            this.condStack.push(this.XCount);

        } else if (obj.equals("&&")) {
            //规范输入为i1
            b = this.condStack.pop();
            a = this.condStack.pop();
            System.out.println("%x" + (++this.XCount) + " =" + " icmp ne i32 %x" + b + ",0");
            this.condStack.push(this.XCount);
            System.out.println("%x" + (++this.XCount) + " =" + " icmp ne i32 %x" + a + ",0");
            this.condStack.push(this.XCount);
            //按位与
            System.out.println("%x" + (++this.XCount) + " =" + " and i1" + " %x" + this.condStack.pop() + ", %x" + this.condStack.pop());
            this.condStack.push(this.XCount);
            //规范结果为i32
            System.out.println("%x" + (++this.XCount) + " =" + " zext i1" + " %x" + this.condStack.pop() + " to i32");
            this.condStack.push(this.XCount);
        } else if (obj.equals("==")) {
            //输入为i32
            //比较
            System.out.println("%x" + (++this.XCount) + " =" + " icmp eq i32 %x" + this.condStack.pop() + ",%x" + this.condStack.pop());
            this.condStack.push(this.XCount);
            //规范结果为i32
            System.out.println("%x" + (++this.XCount) + " =" + " zext i1" + " %x" + this.condStack.pop() + " to i32");
            this.condStack.push(this.XCount);
        } else if (obj.equals("!=")) {
            //输入为i32
            //比较
            System.out.println("%x" + (++this.XCount) + " =" + " icmp ne i32 %x" + this.condStack.pop() + ",%x" + this.condStack.pop());
            this.condStack.push(this.XCount);
            //规范结果为i32
            System.out.println("%x" + (++this.XCount) + " =" + " zext i1" + " %x" + this.condStack.pop() + " to i32");
            this.condStack.push(this.XCount);
        } else if (obj.equals("<")) {
            b = this.condStack.pop();
            a = this.condStack.pop();
            //输入为i32
            //比较
            System.out.println("%x" + (++this.XCount) + " =" + " icmp slt i32 %x" + a + ",%x" + b);
            this.condStack.push(this.XCount);
            //规范结果为i32
            System.out.println("%x" + (++this.XCount) + " =" + " zext i1" + " %x" + this.condStack.pop() + " to i32");
            this.condStack.push(this.XCount);
        } else if (obj.equals(">")) {
            b = this.condStack.pop();
            a = this.condStack.pop();
            //输入为i32
            //比较
            System.out.println("%x" + (++this.XCount) + " =" + " icmp sgt i32 %x" + a + ",%x" + b);
            this.condStack.push(this.XCount);
            //规范结果为i32
            System.out.println("%x" + (++this.XCount) + " =" + " zext i1" + " %x" + this.condStack.pop() + " to i32");
            this.condStack.push(this.XCount);
        } else if (obj.equals("<=")) {
            b = this.condStack.pop();
            a = this.condStack.pop();
            //输入为i32
            //比较
            System.out.println("%x" + (++this.XCount) + " =" + " icmp sle i32 %x" + a + ",%x" + b);
            this.condStack.push(this.XCount);
            //规范结果为i32
            System.out.println("%x" + (++this.XCount) + " =" + " zext i1" + " %x" + this.condStack.pop() + " to i32");
            this.condStack.push(this.XCount);
        } else if (obj.equals(">=")) {
            b = this.condStack.pop();
            a = this.condStack.pop();
            //输入为i32
            //比较
            System.out.println("%x" + (++this.XCount) + " =" + " icmp sge i32 %x" + a + ",%x" + b);
            this.condStack.push(this.XCount);
            //规范结果为i32
            System.out.println("%x" + (++this.XCount) + " =" + " zext i1" + " %x" + this.condStack.pop() + " to i32");
            this.condStack.push(this.XCount);
        }
    }

    public void exp(int functionMode, boolean isPtr) {//functionMode=1则为从函数进入，为2则为从cond进入
        Stack<String> stack = new Stack<String>();
        Stack<Integer> numStack = new Stack<Integer>();                         //exp中记录最近的结果
        tokenUtils.getNext();
        int flag = 0, NumCount = 0, leftCount = 1;
        Object NValue = 0;
        if (functionMode == 1) {
            stack.push("(");
        }
        while (functionMode != 1 || leftCount > 0) {
            flag = 0;
            if (stack.empty() && !tokenUtils.isInExp(tokenUtils.getCurrent())) {
                if (NumCount != 1) {
                    System.exit(42);
                }
                break;
            }
            if (stack.empty()) {
                if (tokenUtils.getCurrent() instanceof Integer || containsIdent(tokenUtils.getCurrent()) || tokenUtils.isFunction(tokenUtils.getCurrent())) {
                    stack.push("NNN");
                    NValue = tokenUtils.getCurrent() instanceof Integer ? (Integer) tokenUtils.getCurrent() : tokenUtils.getCurrent();
                    NumCount++;
                    tokenUtils.getNext();
                } else if (tokenUtils.getCurrent().equals(")")) {
                    if (functionMode == 2) {
                        break;
                    }
                    System.exit(43);
                } else {
                    stack.push((String) tokenUtils.getCurrent());
                    tokenUtils.getNext();
                }
            } else if (!tokenUtils.isInExp(tokenUtils.getCurrent())) {
                if (stack.peek().equals("(")) {
                    if (functionMode == 1 && tokenUtils.getCurrent().equals(",")) {
                        tokenUtils.getBack();
                        return;
                    }
                    System.exit(44);
                } else {
                    if (!(stack.peek().equals("NNN") || stack.peek().equals(")") || stack.peek().equals("++") || stack.peek().equals("--") || stack.peek().equals("!"))) {
                        NumCount--;
                    }
                    if (stack.peek().equals(")")) {
                        stack.pop();
                        leftCount--;
                    }
                    if (stack.peek().equals("NNN")) {
                        expPrint(numStack, NValue, functionMode, isPtr);
                    }
                    expPrint(numStack, stack.pop(), functionMode, isPtr);
                }
            } else {
                if (tokenUtils.getIsPush().get(stack.peek()) != null) {
                    for (String string : tokenUtils.getIsPush().get(stack.peek())) {
                        if (tokenUtils.getCurrent().equals(string) ||
                                ((tokenUtils.getCurrent() instanceof Integer || containsIdent(tokenUtils.getCurrent()) || tokenUtils.isFunction(tokenUtils.getCurrent())) && string.equals("NNN"))) {
                            stack.push(string);
                            if (string.equals("NNN")) {
                                NValue = tokenUtils.getCurrent() instanceof Integer ? (Integer) tokenUtils.getCurrent() : tokenUtils.getCurrent();
                                NumCount++;
                            }
                            if (string.equals("(")) {
                                leftCount++;
                            }
                            tokenUtils.getNext();
                            flag = 1;
                            break;
                        }
                    }
                }
                if (flag != 1) {
                    for (String string : tokenUtils.getIsPop().get(stack.peek())) {
                        if (tokenUtils.getCurrent().equals(string) ||
                                ((tokenUtils.getCurrent() instanceof Integer || containsIdent(tokenUtils.getCurrent())) && string.equals("NNN")) ||
                                (tokenUtils.isFunction(NValue) && tokenUtils.getCurrent().equals("("))) {
                            if (!(stack.peek().equals("NNN") || stack.peek().equals(")") || stack.peek().equals("++") || stack.peek().equals("--") || stack.peek().equals("!"))) {
                                NumCount--;
                            }
                            if (stack.peek().equals(")")) {
                                stack.pop();
                                leftCount--;
                            }
                            if (stack.peek().equals("NNN")) {
                                expPrint(numStack, NValue, functionMode, isPtr);
                            }
                            expPrint(numStack, stack.pop(), functionMode, isPtr);
                            flag = 1;
                            break;
                        }
                    }
                    if (flag == 0) {
                        System.exit(45);
                    }
                }
            }
        }
        if (functionMode != 1) {
            tokenUtils.getBack();
        }

    }

    public int getArrayPtr(Object obj, int mode) {
        List<Object> arrayList;
        if (containsArray(obj)) {
            arrayList = (List<Object>) getArrayValue(obj);
        } else {
            arrayList = (List<Object>) getConstArrayValue(obj);
        }

        List<Integer> indexList = new ArrayList<Integer>();
        int len = arrayLenth(arrayList);
        int dimensionTag = arrayList.size() - 1;
        int dimension = 0;
        if (!tokenUtils.getCurrent().equals("[")) {
            if (mode == 1) {
                int ptr = ++this.XCount;
                if (isParam(obj)) {
                    System.out.println("%x" + (this.XCount) + " = getelementptr i32, i32* %x" + arrayList.get(0) + ", i32 0");
                } else {
                    if (arrayList.get(0) instanceof Integer) {
                        System.out.println("%x" + (this.XCount) + " = getelementptr [" + len + " x i32], [" + len + " x i32]* %x" + arrayList.get(0) + ", i32 0, i32 0");
                    } else {
                        System.out.println("%x" + (this.XCount) + " = getelementptr [" + len + " x i32], [" + len + " x i32]* " + arrayList.get(0) + ", i32 0, i32 0");
                    }
                }
                return ptr;
            }
            System.exit(57);
        }
        tokenUtils.getBack();
        for (dimension = 0; tokenUtils.getNext().equals("["); dimension++) {
            this.exp(0, false);
            indexList.add(this.XCount);
            if (!tokenUtils.getNext().equals("]")) {
                System.exit(58);
            }
        }
        if (mode != 1 && dimension != dimensionTag) {
            System.exit(59);
        }
        int indexListLen = indexList.size();
        int index = 0;
        int lastIndex = ++this.XCount;
        System.out.println("%x" + (this.XCount) + " = add i32 0, 0");
        for (int i = 0; i < indexListLen; i++) {
            int indexRaw = 1;
            for (int j = dimensionTag; j > i + 1; j--) {
                indexRaw *= (int) arrayList.get(j);
            }
            int mulResult = ++this.XCount;
            System.out.println("%x" + (this.XCount) + " =" + " mul i32" + " %x" + indexList.get(i) + ", " + indexRaw);
            index = ++this.XCount;
            System.out.println("%x" + (this.XCount) + " =" + " add i32" + " %x" + lastIndex + ", %x" + mulResult);
            lastIndex = index;
        }
        int ptr = ++this.XCount;
        if (isParam(obj)) {
            System.out.println("%x" + (this.XCount) + " = getelementptr i32, i32* %x" + arrayList.get(0) + ", i32 %x" + index);
        } else {
            if (arrayList.get(0) instanceof Integer) {
                System.out.println("%x" + (this.XCount) + " = getelementptr [" + len + " x i32], [" + len + " x i32]* %x" + arrayList.get(0) + ", i32 0, i32 %x" + index);
            } else {
                System.out.println("%x" + (this.XCount) + " = getelementptr [" + len + " x i32], [" + len + " x i32]* " + arrayList.get(0) + ", i32 0, i32 %x" + index);
            }
        }
        return ptr;
    }

    public void checkDimension(String funcName, int pos) {
        int initPos = tokenUtils.getCurrentPosition();
        Object ident = tokenUtils.peek();

        if (!containsArray(ident)) {
            return;
        }

        int need = funcParamsMap.get(funcName).get(pos - 1);
        int dimension = ((List<Integer>) getArrayValue(ident)).size() - 1;
        int leftCnt = 0;
        while (!tokenUtils.getNext().equals(",") && !tokenUtils.getCurrent().equals(")")) {
            if (tokenUtils.getCurrent().equals("[")) {
                leftCnt++;
            }
        }
        if (need != dimension - leftCnt) {
            System.exit(71);
        }
        tokenUtils.setCurrentPosition(initPos);
    }

    public List<Integer> getFuncParams(Object obj, Stack<Integer> numStack) {
        List<Integer> result = new ArrayList<Integer>();
        List<String> args = tokenUtils.getFuncIdent().get(obj);
        List<Integer> paramsDimension = funcParamsMap.get(obj);
        int i = 1;
        if (args.size() == 1) {
            return result;
        }
        do {
            Object ident = tokenUtils.peek();
            if (!args.get(i).equals("i32")) {
                checkDimension((String) obj, i);
            }
            this.exp(1, !args.get(i).equals("i32"));
            result.add(this.XCount);
            i++;
        } while (i != args.size() && tokenUtils.getNext().equals(","));
        return result;
    }


    public void expPrint(Stack<Integer> numStack, Object obj, int mode, boolean isPtr) {
        Integer a, b;
        if (obj instanceof Integer) {
            System.out.println("%x" + (++this.XCount) + " =" + " add i32" + " 0" + ", " + (Integer) obj);
            numStack.push(this.XCount);
        } else if (obj.equals("+")) {
            System.out.println("%x" + (++this.XCount) + " =" + " add i32" + " %x" + numStack.pop() + ", %x" + numStack.pop());
            numStack.push(this.XCount);
        } else if (obj.equals("-")) {
            b = numStack.pop();
            a = numStack.pop();
            System.out.println("%x" + (++this.XCount) + " =" + " sub i32" + " %x" + a + ", %x" + b);
            numStack.push(this.XCount);
        } else if (obj.equals("*")) {
            System.out.println("%x" + (++this.XCount) + " =" + " mul i32" + " %x" + numStack.pop() + ", %x" + numStack.pop());
            numStack.push(this.XCount);
        } else if (obj.equals("/")) {
            b = numStack.pop();
            a = numStack.pop();
            System.out.println("%x" + (++this.XCount) + " =" + " sdiv i32" + " %x" + a + ", %x" + b);
            numStack.push(this.XCount);
        } else if (obj.equals("%")) {
            b = numStack.pop();
            a = numStack.pop();
            System.out.println("%x" + (++this.XCount) + " =" + " srem i32" + " %x" + a + ", %x" + b);
            numStack.push(this.XCount);
        } else if (obj.equals("--")) {
            System.out.println("%x" + (++this.XCount) + " =" + " sub i32" + " 0" + ", %x" + numStack.pop());
            numStack.push(this.XCount);
        } else if (obj.equals("!")) {
            System.out.println("%x" + (++this.XCount) + " =" + " icmp eq i32 0," + "%x" + numStack.pop());
            numStack.push(this.XCount);
            System.out.println("%x" + (++this.XCount) + " =" + " zext i1" + " %x" + numStack.pop() + " to i32");
            numStack.push(this.XCount);
        } else if (tokenUtils.isIdent((obj))) {
            if (containsIdent(obj) && !tokenUtils.isFunction(obj) && !containsArray(obj) && !containsConstArray(obj)) {
                if (getIdentValue(obj) instanceof Integer) {                          //如果是局部变量
                    System.out.println("%x" + (++this.XCount) + " =" + " load i32" + ", i32* %x" + (Integer) getIdentValue(obj));
                } else {                                                              //如果是全局变量
                    System.out.println("%x" + (++this.XCount) + " =" + " load i32" + ", i32* " + (String) getIdentValue(obj));
                }
                numStack.push(this.XCount);
            } else if (tokenUtils.isFunction(obj)) {
                if (!tokenUtils.getCurrent().equals("(")) {
                    System.exit(46);
                }

                List<Integer> params = getFuncParams(obj, numStack);
                List<String> args = tokenUtils.getFuncIdent().get(obj);
                if (args.size() - 1 != params.size()) {
                    System.exit(70);
                }

                if (args.get(0).equals("i32")) {
                    System.out.print("%x" + (++this.XCount) + " = ");
                    numStack.push(this.XCount);
                }
                System.out.print("call " + args.get(0) + " @" + obj + "(");
                for (int i = 1; i < args.size(); i++) {
                    System.out.print(args.get(i) + " %x" + params.get(i - 1));
                    if (i != args.size() - 1) {
                        System.out.print(", ");
                    }
                }

                System.out.println(")");
            } else if (containsArray(obj) || containsConstArray(obj)) {
                int ptr = getArrayPtr(obj, mode);
                if (!isPtr) {
                    System.out.println("%x" + (++this.XCount) + " =" + " load i32" + ", i32* %x" + ptr);
                    numStack.push(this.XCount);
                }
            }
        }
    }

    public int globalExp() { //折叠
        Stack<String> stack = new Stack<String>();
        Stack<Integer> numStack = new Stack<Integer>();
        tokenUtils.getNext();
        int flag = 0, NumCount = 0;
        Integer NValue = 0;
        while (true) {
            flag = 0;
            if (stack.empty() && !tokenUtils.isInExp(tokenUtils.getCurrent())) {
                if (NumCount != 1) {
                    System.exit(47);
                }
                break;
            }
            if (stack.empty()) {
                if (tokenUtils.getCurrent() instanceof Integer || containsIdent(tokenUtils.getCurrent())) {
                    stack.push("NNN");
                    NValue = tokenUtils.getCurrent() instanceof Integer ? (Integer) tokenUtils.getCurrent() : globalExpMap.get(tokenUtils.getCurrent());
                    numStack.push(NValue);
                    NumCount++;
                    tokenUtils.getNext();
                } else if (tokenUtils.getCurrent().equals(")")) {
                    System.exit(48);
                } else {
                    stack.push((String) tokenUtils.getCurrent());
                    tokenUtils.getNext();
                }
            } else if (!tokenUtils.isInExp(tokenUtils.getCurrent())) {
                if (stack.peek().equals("(")) {
                    System.exit(49);
                } else {
                    if (!(stack.peek().equals("NNN") || stack.peek().equals(")") || stack.peek().equals("++") || stack.peek().equals("--") || stack.peek().equals("!"))) {
                        NumCount--;
                    }
                    if (stack.peek().equals(")")) {
                        stack.pop();
                    }
                    if (stack.peek().equals("NNN")) {
                        calValue(numStack, NValue);
                    }
                    calValue(numStack, stack.pop());
                }
            } else {
                if (tokenUtils.getIsPush().get(stack.peek()) != null) {
                    for (String string : tokenUtils.getIsPush().get(stack.peek())) {
                        if (tokenUtils.getCurrent().equals(string) ||
                                ((tokenUtils.getCurrent() instanceof Integer || containsIdent(tokenUtils.getCurrent())) && string.equals("NNN"))) {
                            stack.push(string);
                            if (string.equals("NNN")) {
                                NValue = tokenUtils.getCurrent() instanceof Integer ? (Integer) tokenUtils.getCurrent() : this.globalExpMap.get(tokenUtils.getCurrent());
                                NumCount++;
                                numStack.push(NValue);
                            }
                            tokenUtils.getNext();
                            flag = 1;
                            break;
                        }
                    }
                }
                if (flag != 1) {
                    for (String string : tokenUtils.getIsPop().get(stack.peek())) {
                        if (tokenUtils.getCurrent().equals(string) ||
                                ((tokenUtils.getCurrent() instanceof Integer || containsIdent(tokenUtils.getCurrent())) && string.equals("NNN")) ||
                                (tokenUtils.isFunction(NValue) && tokenUtils.getCurrent().equals("("))) {
                            if (!(stack.peek().equals("NNN") || stack.peek().equals(")") || stack.peek().equals("++") || stack.peek().equals("--") || stack.peek().equals("!"))) {
                                NumCount--;
                            }
                            if (stack.peek().equals(")")) {
                                stack.pop();
                            }
                            if (stack.peek().equals("NNN")) {
                                calValue(numStack, NValue);
                            }
                            calValue(numStack, stack.pop());
                            flag = 1;
                            break;
                        }
                    }
                    if (flag == 0) {
                        System.exit(50);
                    }
                }
            }
        }
        tokenUtils.getBack();
        return numStack.pop();
    }

    void calValue(Stack<Integer> stack, Object obj) {
        Integer a, b;
        if (obj.equals("+")) {
            b = stack.pop();
            a = stack.pop();
            stack.push(a + b);
        } else if (obj.equals("-")) {
            b = stack.pop();
            a = stack.pop();
            stack.push(a - b);
        } else if (obj.equals("*")) {
            b = stack.pop();
            a = stack.pop();
            stack.push(a * b);
        } else if (obj.equals("/")) {
            b = stack.pop();
            a = stack.pop();
            stack.push(a / b);
        } else if (obj.equals("%")) {
            b = stack.pop();
            a = stack.pop();
            stack.push(a % b);
        } else if (obj.equals("--")) {
            a = stack.pop();
            stack.push(0 - a);
        }
    }

    public void funcDef() {
        System.out.print("define ");
        List<String> funcList = this.funcType();
        if (!tokenUtils.isIdent(tokenUtils.getNext())) {
            System.exit(62);
        }
        String funcName = (String) tokenUtils.getCurrent();
        System.out.print("@" + funcName);
        if (!tokenUtils.getNext().equals("(")) {
            System.exit(63);
        }
        System.out.print("(");
        if (!tokenUtils.peek().equals(")")) {
            List<Object> detailList = this.funcFParams(funcName);
            funcList.addAll((List<String>) detailList.get(0));
            Map<String, Object> identMap = (Map<String, Object>) detailList.get(1);
            Map<String, Object> arrayMap = (Map<String, Object>) detailList.get(2);

            if (!tokenUtils.getNext().equals(")")) {
                System.exit(64);
            }
            System.out.println(")");
            tokenUtils.getFuncIdent().put(funcName, funcList);
            System.out.println("{");
            this.block(false, identMap, arrayMap, 1, funcName);
        } else {
            tokenUtils.getNext();
            System.out.println(")");
            tokenUtils.getFuncIdent().put(funcName, funcList);
            System.out.println("{");
            this.block(false, new HashMap<String, Object>(), new HashMap<String, Object>(), 1, funcName);
        }
        System.out.println("}");

    }

    public List<String> funcType() {
        List<String> list = new ArrayList<String>();
        if (!tokenUtils.getNext().equals("void") && !tokenUtils.getCurrent().equals("int")) {
            System.exit(61);
        }
        System.out.print(tokenUtils.getCurrent().equals("void") ? "void " : "i32 ");
        list.add(tokenUtils.getCurrent().equals("void") ? "void" : "i32");
        return list;
    }

    public List<Object> funcFParams(String funcName) {
        List<Object> resultList = new ArrayList<Object>();
        Map<String, Object> identMap = new HashMap<String, Object>();
        Map<String, Object> arrayMap = new HashMap<String, Object>();
        List<String> paramsType = new ArrayList<String>();
        List<Integer> paramsDimension = new ArrayList<Integer>();

        String name0 = (String) tokenUtils.peekTwo();
        paramsType.add(tokenUtils.peekThree().equals("[") ? "i32*" : "i32");
        Object obj0 = this.funcFParam();
        if (obj0 instanceof Integer) {
            identMap.put(name0, obj0);
            paramsDimension.add(0);
        } else {
            identMap.put(name0, ((List<Integer>) obj0).get(0));
            arrayMap.put(name0, obj0);
            paramsDimension.add(((List<Integer>) obj0).size() - 1);
        }

        while (tokenUtils.peek().equals(",")) {
            tokenUtils.getNext();
            System.out.print(", ");
            String name = (String) tokenUtils.peekTwo();
            paramsType.add(tokenUtils.peekThree().equals("[") ? "i32*" : "i32");
            Object obj = this.funcFParam();
            if (obj instanceof Integer) {
                identMap.put(name, obj);
                paramsDimension.add(0);
            } else {
                identMap.put(name, ((List<Integer>) obj).get(0));
                arrayMap.put(name, obj);
                paramsDimension.add(((List<Integer>) obj).size() - 1);
            }
        }
        funcParamsMap.put(funcName, paramsDimension);
        resultList.add(paramsType);
        resultList.add(identMap);
        resultList.add(arrayMap);
        return resultList;
    }

    public Object funcFParam() {
        List arrayList = null;
        if (!tokenUtils.getNext().equals("int")) {
            System.exit(65);
        }
        System.out.print("i32");
        if (!tokenUtils.isIdent(tokenUtils.getNext())) {
            System.exit(66);
        }
        int id = ++this.XCount;
        if (tokenUtils.peek().equals("[")) {
            System.out.print("*");
            tokenUtils.getNext();
            arrayList = new ArrayList<Object>();
            arrayList.add(id);
            if (!tokenUtils.getNext().equals("]")) {
                System.exit(67);
            }
            arrayList.add(0);
            while (tokenUtils.peek().equals("[")) {
                tokenUtils.getNext();
                //检查是否在编译期可求值
                for (int i = tokenUtils.getCurrentPosition(); !(tokenUtils.getAllText().get(i).equals("]") || tokenUtils.getAllText().get(i).equals(";")); i++) {
                    if (containsIdent(tokenUtils.getAllText().get(i)) && !containsConstIdent(tokenUtils.getAllText().get(i))
                            || tokenUtils.getFuncIdent().containsKey(tokenUtils.getAllText().get(i))) {
                        System.exit(68);
                    }
                }
                int value = this.globalExp();
                if (!tokenUtils.getNext().equals("]")) {
                    System.exit(69);
                }
                arrayList.add(value);
            }
        }
        System.out.print(" %x" + id);
        return arrayList != null ? arrayList : id;
    }
}

